package com.stephen.bp.websocket;

import java.net.InetSocketAddress;
import java.util.concurrent.ConcurrentHashMap;

import com.alibaba.fastjson.JSONObject;
import com.stephen.bp.model.RequestAndResponse;
import com.stephen.bp.model.UserChannel;
import com.stephen.bp.service.RoomService;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;

/**
 * @author qiuwenwei
 */
@Component
@ChannelHandler.Sharable
@AllArgsConstructor
@Log4j2
public class WebSocketServerHandler extends SimpleChannelInboundHandler<WebSocketFrame> {

    private final RoomService roomService;

    public static boolean start = false;

    private final static ConcurrentHashMap<String, Long> TIME_MAP = new ConcurrentHashMap<>();

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {

    }

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, WebSocketFrame webSocketFrame) {
        try {
            // 判断消息类型
            if (webSocketFrame instanceof TextWebSocketFrame) {
                String username;
                String text = ((TextWebSocketFrame) webSocketFrame).text();
                RequestAndResponse requestAndResponse = JSONObject.parseObject(text, RequestAndResponse.class);
                log.info("请求用户{},请求参数:{}", UserChannel.getUserNameByChannel(channelHandlerContext.channel()), JSONObject.toJSONString(requestAndResponse));
                switch (requestAndResponse.getAction()) {
                    case LOGIN:
                        String loginUsername = requestAndResponse.getContent();
                        if (!same(UserChannel.getChannelByUsername(loginUsername), channelHandlerContext.channel())) {
                            UserChannel.kick(loginUsername);
                        }
                        UserChannel.updateChannel(loginUsername, channelHandlerContext.channel());
                        UserChannel.writeAndFlush0(loginUsername, requestAndResponse);
                        break;
                    case JOIN_ROOM:
                        username = UserChannel.getUserNameByChannel(channelHandlerContext.channel());
                        if (username == null) {
                            return;
                        }
                        if (!start) {
                            UserChannel.notStart(username);
                            return;
                        }
                        roomService.join(username, requestAndResponse);
                        break;
                    case SELECT_ROLE:
                        username = UserChannel.getUserNameByChannel(channelHandlerContext.channel());
                        if (username == null) {
                            return;
                        }
                        roomService.selectRole(username, requestAndResponse.getRoomId(), requestAndResponse.getContent());
                        break;
                    case START:
                        username = UserChannel.getUserNameByChannel(channelHandlerContext.channel());
                        if (username == null) {
                            return;
                        }
                        if (requestAndResponse.getRoomId() == null) {
                            return;
                        }
                        roomService.start(username, requestAndResponse.getRoomId());
                        break;
                    case DECISION:
                        username = UserChannel.getUserNameByChannel(channelHandlerContext.channel());
                        if (username == null) {
                            return;
                        }
                        if (limit(username)) {
                            log.error("请求用户{},请求频率过快,请求内容{}", username, JSONObject.toJSONString(requestAndResponse));
                            return;
                        }
                        roomService.decision(username, requestAndResponse.getRoomId(), requestAndResponse.getContent(), false);
                        break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private boolean limit(String username) {
        //判断用户是否有操作
        if (TIME_MAP.containsKey(username)) {
            //判断上次操作距离本次操作是否超过1秒
            if (System.currentTimeMillis() - TIME_MAP.get(username) > 1000) {
                //如果已经超过一秒放行，记录时间
                TIME_MAP.put(username, System.currentTimeMillis());
                return false;
            } else {
                //如果不到一秒，不放行，不记录时间
                return true;
            }
        } else {
            TIME_MAP.put(username, System.currentTimeMillis());
            return false;
        }
    }

    private boolean same(Channel channel1, Channel channel2) {
        String clientIp1;
        String clientIp2;
        try {
            clientIp1 = ((InetSocketAddress) channel1.remoteAddress()).getAddress().getHostAddress();
            clientIp2 = ((InetSocketAddress) channel2.remoteAddress()).getAddress().getHostAddress();
        } catch (Exception e) {
            return false;
        }
        return clientIp1.equals(clientIp2);
    }
}
